﻿using System;

namespace WiMo.Games
{
    public struct Vector2
    {
        private float _x;
        private float _y;
        private Location _point;

        public Vector2(int x, int y) 
        {
            _x = x;
            _y = y;
            _point = new Location(x, y);
        }

        public Vector2(float x, float y)
        {
            _x = x;
            _y = y;
            _point = new Location((int)x, (int)y);
        }

        public Vector2(PointF point)
        {
            _x = point.X;
            _y = point.Y;
            _point = new Location((int)point.X, (int)point.Y);
        }

        public Vector2(Location point)
        {
            _x = point.X;
            _y = point.Y;
            _point = new Location((int)point.X, (int)point.Y);
        }

        public float X { get { return _x; } set { _x = value; _point.X = (int)value; } }
        public float Y { get { return _y; } set { _y = value; _point.Y = (int)value; } }

        /// <summary>
        /// returns a point instance, useful to not have to cast the float value to an integer.
        /// </summary>
        public Location Point
        {
            get { return _point; }
        }

        public void Abs()
        {
            _x = Math.Abs(_x);
            _y = Math.Abs(_y);
        }

        public float FindNormalAngle()
        {
            return Direction + (float)(Math.PI / 2);
        }

        public float Magnitude
        {
            get{return (float)Math.Sqrt((double)(X * X + Y * Y));}
        }

        public static float Distance(Vector2 vector1, Vector2 vector2)
        {
            var delta = vector2 - vector1;

            return (float)Math.Sqrt((double)(delta.X * delta.X + delta.Y * delta.Y));
        }

        public float Direction
        {
            get
            {
                var theta = Math.PI / 2;

                if(X != 0.0f)
                    theta = Math.Atan(Convert.ToSingle( Y / X));

                if (Y >= 0)
                {
                    if (X >= 0)
                        return (float)theta;                        
                    else
                        return (float)(Math.PI + theta);
                        
                }
                else if(X <= 0)
                        return (float)(Math.PI + theta);
                    else
                        return (float)(2 * Math.PI + theta);

                
            }
        }

        public static Vector2 One
        {
            get { return new Vector2(1, 1); }
        }

        public static Vector2 Zero
        {
            get { return new Vector2(0, 0); }
        }

        public static Vector2 operator -(Vector2 value)
        {
            value.X = -value.X;
            value.Y = -value.Y;
            return value;
        }

        public static Location operator +(Location p1, Vector2 v1)
        {
            return new Location(p1.X + v1.Point.X, p1.Y + v1.Point.Y);
        }

        public static Vector2 operator -(Vector2 v1, Location p1)
        {
            return new Vector2(v1.Point.X - p1.X, v1.Point.Y - p1.Y);
        }

        public static bool operator ==(Vector2 value1, Vector2 value2)
        {
            return value1.X == value2.X && value1.Y == value2.Y;
        }

        public override bool Equals(object vector)
        {            
            return this.GetHashCode() == vector.GetHashCode();
        }

        public override int GetHashCode()
        {
            return (int)(X * Y);
        }

        public static bool operator !=(Vector2 value1, Vector2 value2)
        {
            return value1.X != value2.X || value1.Y != value2.Y;
        }


        public static Vector2 operator +(Vector2 value1, Vector2 value2)
        {
            value1.X += value2.X;
            value1.Y += value2.Y;
            return value1;
        }


        public static Vector2 operator -(Vector2 value1, Vector2 value2)
        {
            value1.X -= value2.X;
            value1.Y -= value2.Y;
            return value1;
        }


        public static Vector2 operator *(Vector2 value1, Vector2 value2)
        {
            value1.X *= value2.X;
            value1.Y *= value2.Y;
            return value1;
        }


        public static Vector2 operator *(Vector2 value, int scaleFactor)
        {
            value.X *= scaleFactor;
            value.Y *= scaleFactor;
            return value;
        }

        public static Vector2 operator *(Vector2 value, float scaleFactor)
        {
            value.X *= scaleFactor;
            value.Y *= scaleFactor;
            return value;
        }

        public static Vector2 operator /(Vector2 value, float scaleFactor)
        {
            value.X /= scaleFactor;
            value.Y /= scaleFactor;
            return value;
        }


        public static Vector2 operator *(int scaleFactor, Vector2 value)
        {
            value.X *= scaleFactor;
            value.Y *= scaleFactor;
            return value;
        }

        public static Vector2 operator *(float scaleFactor, Vector2 value)
        {
            value.X *= scaleFactor;
            value.Y *= scaleFactor;
            return value;
        }

        public static Vector2 operator /(Vector2 value1, Vector2 value2)
        {
            value1.X /= value2.X;
            value1.Y /= value2.Y;
            return value1;
        }


        public static Vector2 operator /(Vector2 value1, int divider)
        {
            value1.X /= divider;
            value1.Y /= divider;
            return value1;
        }

        public static Vector2 operator +(Vector2 left, Location right)
        {
            return new Vector2(left.X + right.X, left.Y + right.Y);
        }

        public static Location operator -(Location left, Vector2 right)
        {
            return new Location(left.X - right.X, left.Y - right.Y);
        }

        public Vector2 Clone()
        {
            return new Vector2(X, Y);
        }

        public override string ToString()
        {
            return string.Format("(X={0} Y={1} Magnitude={2} Direction={3})", X, Y, Magnitude, Direction);
        }
    }
}
